#include "schedulewidget.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTableWidget>
#include <QPushButton>
#include <QComboBox>
#include <QLabel>
#include <QDate>
#include <QDateEdit>
#include <QHeaderView>
#include <QSqlQuery>
#include <QSqlError>
#include <QMessageBox>
#include <QInputDialog>
#include <QFormLayout>
#include <QDialog>
#include <QDialogButtonBox>
#include <QTimeEdit>
#include <QTableWidgetItem>

//构造函数
ScheduleWidget::ScheduleWidget(QWidget *parent)
    : QWidget(parent)
{
    //设置objectName
    setObjectName("ScheduleWidget");

    layoutInit();
    loadSchedule();
}

//布局初始化
void ScheduleWidget::layoutInit(void)
{
    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    
    QHBoxLayout *headerLayout = new QHBoxLayout();
    QLabel *labelYuer = new QLabel(tr("Year:"));
    m_comboBoxYear = new QComboBox();
    //索引改变时加载课程表
    connect(m_comboBoxYear, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ScheduleWidget::loadSchedule);

    QLabel *labelWeek = new QLabel(tr("Week:"));
    m_comboBoxWeek = new QComboBox();
    //索引改变时加载课程表
    connect(m_comboBoxWeek, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ScheduleWidget::loadSchedule);

    m_labelDateRange = new QLabel(tr("Date Range:"));
    headerLayout->addWidget(labelYuer);
    headerLayout->addWidget(m_comboBoxYear);
    headerLayout->addWidget(labelWeek);
    headerLayout->addWidget(m_comboBoxWeek);
    headerLayout->addWidget(m_labelDateRange);
    headerLayout->addStretch();  //添加弹性空间
    mainLayout->addLayout(headerLayout);

    //获取当前年份
    int currentYear = QDate::currentDate().year();
    //获取当前周数
    //QDate::currentDate().weekNumber();说是系统提供的周数与这个周数有差异
    int currentWeek = customWeekNumber(QDate::currentDate());
    //失能m_comboBoxYear信号发送
    m_comboBoxYear->blockSignals(true);  //锁定信号
    //设置年份下拉框
    for (int year = currentYear - 5; year <= currentYear + 5; ++year) {
        m_comboBoxYear->addItem(QString::number(year), year);
    }
    m_comboBoxYear->setCurrentText(QString::number(currentYear));  //设置当前年份
    m_comboBoxYear->blockSignals(false);  //解锁信号

    //失能m_comboBoxWeek信号发送
    m_comboBoxWeek->blockSignals(true);  //锁定信号
    //设置周数下拉框
    for (int week = 1; week <= 52; ++week) {
        m_comboBoxWeek->addItem(QString("Week %1").arg(week), week);
    }
    //设置当前周数
    m_comboBoxWeek->setCurrentText(QString("Week %1").arg(currentWeek));  //设置当前周数
    m_comboBoxWeek->blockSignals(false);  //解锁信号

    QPair<QDate, QDate> weekRange = getWeekRange(currentYear, currentWeek);
    m_labelDateRange->setText(tr("Date Range: %1 - %2").arg(weekRange.first.toString("yyyy/MM/dd")).arg(weekRange.second.toString("yyyy/MM/dd")));  //设置日期范围

    //课程表
    QStringList days = QStringList() << tr("Monday") << tr("Tuesday") << tr("Wednesday") << tr("Thursday") << tr("Friday") << tr("Saturday") << tr("Sunday");
    m_times = QStringList() << tr("9:00-10:30") << tr("11:00-13:30") << tr("14:00-15:30") << tr("16:00-18:30") << tr("19:00-20:30") << tr("21:00-22:30");
    QStringList headerLabels;
    QDate startDate = weekRange.first;
    for (int i = 0; i < days.count(); ++i) {
        QDate currentDate = startDate.addDays(i);
        headerLabels << QString("%1\n%2").arg(days.at(i)).arg(currentDate.toString("MM/dd"));
    }

    m_tableWidget = new QTableWidget(headerLabels.count(), m_times.count(), this);
    m_tableWidget->setVerticalHeaderLabels(headerLabels);
    m_tableWidget->setHorizontalHeaderLabels(m_times);
    m_tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);  //设置水平表头的伸缩模式
    m_tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);  //设置垂直表头的伸缩模式
    m_tableWidget->setAlternatingRowColors(true);  //设置交替行颜色
    m_tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);  //设置单个选择，不能选择一行或者一列
    m_tableWidget->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);  //设置双击编辑或者按下F2键编辑
    //添加课程表到布局
    mainLayout->addWidget(m_tableWidget);  //后面的1表示拉伸因子，它控制控件在布局方向上的空间分配比例
    connect(m_tableWidget, &QTableWidget::itemChanged, this, &ScheduleWidget::handleItemChanged);

    //水平布局
    QHBoxLayout *buttonLayout = new QHBoxLayout();
    m_pushButtonPrevWeek = new QPushButton(tr("Prev Week"));
    //按钮点击时加载课程表
    connect(m_pushButtonPrevWeek, &QPushButton::clicked, this, [=]() {
        int weekIndex = m_comboBoxWeek->currentIndex();
        int yearIndex = m_comboBoxYear->currentIndex();
        if (weekIndex > 0) {
            m_comboBoxWeek->setCurrentText(QString("Week %1").arg(weekIndex - 1));
        }else if (yearIndex > 0){
            m_comboBoxYear->setCurrentIndex(yearIndex - 1);
            m_comboBoxWeek->setCurrentIndex(51);
        }
    });
    m_pushButtonNextWeek = new QPushButton(tr("Next Week"));
    //按钮点击时加载课程表
    connect(m_pushButtonNextWeek, &QPushButton::clicked, this, [=]() {
        int weekIndex = m_comboBoxWeek->currentIndex();
        int yearIndex = m_comboBoxYear->currentIndex();
        if (weekIndex < 51) {
            m_comboBoxWeek->setCurrentIndex(weekIndex + 1);
        }
        else if (yearIndex > m_comboBoxYear->count() - 1)
        {
            m_comboBoxYear->setCurrentIndex(yearIndex + 1);
            m_comboBoxWeek->setCurrentIndex(0);
        }
    });
    m_pushButtonAdd = new QPushButton(tr("Add Schedule"));
    //按钮点击时添加课程
    connect(m_pushButtonAdd, &QPushButton::clicked, this, &ScheduleWidget::addCourse);
    m_pushButtonDel = new QPushButton(tr("Del Schedule"));
    //按钮点击时删除课程
    connect(m_pushButtonDel, &QPushButton::clicked, this, &ScheduleWidget::deleteCourse);
    //设置按钮固定宽度200
    m_pushButtonPrevWeek->setFixedWidth(200);
    m_pushButtonNextWeek->setFixedWidth(200);
    m_pushButtonAdd->setFixedWidth(200);
    m_pushButtonDel->setFixedWidth(200);
    //添加弹簧
    buttonLayout->addStretch();  //添加弹性空间
    buttonLayout->addWidget(m_pushButtonPrevWeek);
    buttonLayout->addWidget(m_pushButtonNextWeek);
    buttonLayout->addWidget(m_pushButtonAdd);
    buttonLayout->addWidget(m_pushButtonDel);
    buttonLayout->addStretch();  //添加弹性空间
    //添加按钮布局到主布局
    mainLayout->addLayout(buttonLayout);
}

int ScheduleWidget::customWeekNumber(const QDate &date) const
{
    //获取当年的第一天
    QDate firstDayOfYear = QDate(date.year(), 1, 1);
    //获取第一天是星期几
    int firstDayOfWeek = firstDayOfYear.dayOfWeek();
    int days = firstDayOfYear.daysTo(date);     //计算从第一天到当前日期的天数
    int weekNumber = (days + firstDayOfWeek - 1) / 7 + 1;  //计算周数
    return weekNumber;
}

//获取当前周的日期范围
QPair<QDate, QDate> ScheduleWidget::getWeekRange(int year, int week) const
{
    //获取当年的第一天
    QDate firstDayOfYear = QDate(year, 1, 1);
    //获取第一天是星期几
    int firstDayOfWeek = firstDayOfYear.dayOfWeek();
    //计算当前周的第一天和最后一天
    QDate startDate = firstDayOfYear.addDays((week - 1) * 7 - (firstDayOfWeek - 1));
    QDate endDate = startDate.addDays(6);
    return qMakePair(startDate, endDate);
}

//加载课程表
void ScheduleWidget::loadSchedule(void)
{
    m_tableWidget->blockSignals(true);  //锁定信号

    m_tableWidget->clearContents();  //清空课程表
    //获取年
    int year = m_comboBoxYear->currentData().toInt();
    //获取周
    int week = m_comboBoxWeek->currentData().toInt();
    //获取周的日期范围
    QPair<QDate, QDate> weekRange = getWeekRange(year, week);
    //开始日期
    QDate startDate = weekRange.first;
    //结束日期
    QDate endDate = weekRange.second;
    //设置日期范围
    m_labelDateRange->setText(tr("Date Range: %1 - %2").arg(startDate.toString("yyyy/MM/dd")).arg(endDate.toString("yyyy/MM/dd")));  //设置日期范围

    //获取课程表数据
    QVector<QVector<QString>> courses(7, QVector<QString>(m_times.count(), ""));

    //查询数据库中这个日期范围内的课程
    QSqlQuery query;
    //按照日期范围查询，并提取日期、时间和课程名称
    query.prepare("SELECT date, time, course_name FROM schedule WHERE date BETWEEN ? AND ?");
    query.addBindValue(startDate.toString("yyyy-MM-dd"));
    query.addBindValue(endDate.toString("yyyy-MM-dd"));
    if (query.exec()) {
        while (query.next()) {
            //获取日期
            QDate date = QDate::fromString(query.value(0).toString(), "yyyy-MM-dd");
            //获取时间
            QString time = query.value(1).toString();
            int dayIndex = startDate.daysTo(date);  //计算日期索引
            int timeIndex = m_times.indexOf(time);  //获取时间索引
            if (dayIndex >= 0 && dayIndex < 7 && timeIndex != -1) {
                //设置课程名称
                courses[dayIndex][timeIndex] = query.value(2).toString();
            }
        }
    }

    //设置课程表数据
    for (int day = 0; day < 7; ++day) {
        for (int time = 0; time < m_times.count(); ++time) {
            QTableWidgetItem *item = new QTableWidgetItem(courses[day][time]);
            item->setTextAlignment(Qt::AlignCenter);  //设置文本居中
            m_tableWidget->setItem(day, time, item);  //设置课程表项
        }
    }

    //取消锁定信号
    m_tableWidget->blockSignals(false);  //解锁信号
}

//添加课程
void ScheduleWidget::addCourse(void)
{
    //当前选中的单元格天数
    int dayIndex = m_tableWidget->currentRow();
    //当前选中的单元格时间
    int timeIndex = m_tableWidget->currentColumn();
    //验证有效性
    if (dayIndex < 0 || dayIndex >= 7 || timeIndex < 0 || timeIndex >= m_times.count()) {
        QMessageBox::warning(this, tr("Warning"), tr("Please select a valid cell!"));
        return;
    }
    //检查时间段是否被占用
    if (!m_tableWidget->item(dayIndex, timeIndex)->text().isEmpty()) {
        QMessageBox::warning(this, tr("Warning"), tr("This time slot is already occupied!"));
        return;
    }

    //创建对话框
    QDialog dialog(this);
    dialog.setWindowTitle(tr("Add Course"));
    //创建布局
    QFormLayout layout(&dialog);
    //学生姓名下拉框
    QComboBox comboBoxStudentName;
    //获取学生姓名
    QSqlQuery nameQuery("SELECT name FROM studentInfo");
    while (nameQuery.next()) {
        comboBoxStudentName.addItem(nameQuery.value(0).toString());
    }
    //时间映射表
    QMap<int, QTime> timeMap = {{0, QTime(9, 0)}, {1, QTime(11, 0)}, {2, QTime(14, 0)}, {3, QTime(16, 0)}, {4, QTime(19, 0)}, {5, QTime(21, 0)}};
    //时间选择框
    QTimeEdit timeEdit;
    //时间格式
    timeEdit.setDisplayFormat("HH:mm");
    //设置默认时间
    timeEdit.setTime(timeMap.value(timeIndex));
    //加入布局
    layout.addRow(tr("Student Name:"), &comboBoxStudentName);
    layout.addRow(tr("Time:"), &timeEdit);
    //添加按钮
    QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
    //设置按键名称
    buttonBox.button(QDialogButtonBox::Ok)->setText(tr("Add"));
    buttonBox.button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
    //加入布局
    layout.addWidget(&buttonBox);
    //连接信号槽
    connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
    connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
    //执行对话框
    if (dialog.exec() != QDialog::Accepted) {
        return;
    }
    //生成组合字符串
    QString courseName = QString("%1 %2").arg(comboBoxStudentName.currentText()).arg(timeEdit.time().toString("HH:mm"));
    //获取日期信息
    int year = m_comboBoxYear->currentData().toInt();
    int week = m_comboBoxWeek->currentData().toInt();
    QPair<QDate, QDate> weekRange = getWeekRange(year, week);
    QDate currentDate = weekRange.first.addDays(dayIndex);  //获取日期
    //获取时间信息
    QString time = m_times.at(timeIndex);  //获取时间
    //数据库操作
    QSqlQuery query;
    query.prepare("INSERT INTO schedule (date, time, course_name) VALUES (?, ?, ?)");
    query.addBindValue(currentDate.toString("yyyy-MM-dd"));  //绑定日期
    query.addBindValue(time);  //绑定时间
    query.addBindValue(courseName);  //绑定课程名称
    //执行插入操作
    if (!query.exec()) {
        QMessageBox::warning(this, tr("Error"), QString(tr("Failed to add course! = ") + query.lastError().text()));
        return;
    }
    //更新课程表
    loadSchedule();
}

//删除课程
void ScheduleWidget::deleteCourse(void)
{
    QMessageBox confirmBox(this);
    confirmBox.setWindowTitle(tr("Confirm Delete"));
    confirmBox.setText(tr("Are you sure you want to delete this course?"));

    //设置按钮
    QPushButton * yesButton = confirmBox.addButton(tr("Yes"), QMessageBox::YesRole);
    QPushButton * noButton = confirmBox.addButton(tr("No"), QMessageBox::NoRole);
    confirmBox.setDefaultButton(noButton);
    confirmBox.exec();

    if (confirmBox.clickedButton() == yesButton) {
        //获取当前选中的单元格
        int dayIndex = m_tableWidget->currentRow();
        int timeIndex = m_tableWidget->currentColumn();
        if (dayIndex == -1 || timeIndex == -1){
            QMessageBox::warning(this, tr("Warning"), tr("Please select a valid cell!"));
            return ;
        }
        QTableWidgetItem *item = m_tableWidget->item(dayIndex, timeIndex);
        if (!item || item->text().isEmpty()){
            QMessageBox::warning(this, tr("Warning"), tr("Please select a valid cell!"));
            return ;
        }

        //获取日期
        int year = m_comboBoxYear->currentData().toInt();
        int week = m_comboBoxWeek->currentData().toInt();
        QPair<QDate, QDate> weekRange = getWeekRange(year, week);
        QDate date = weekRange.first.addDays(dayIndex);
        QString time = m_times.at(timeIndex);

        QSqlQuery query;
        query.prepare("DELETE FROM schedule WHERE date = ? AND time = ?");
        query.addBindValue(date.toString("yyyy-MM-dd"));
        query.addBindValue(time);
        if (!query.exec()) {
            QMessageBox::warning(this, tr("Error"), QString(tr("Failed to delete course! = ") + query.lastError().text()));
        }else{
            loadSchedule();
        }
    }
}

void ScheduleWidget::handleItemChanged(QTableWidgetItem *item)
{
    //获取天
    int day = item->row();
    //获取时间
    int timeSlot = item->column();
    QString courseName = item->text().trimmed();

    int year = m_comboBoxYear->currentData().toInt();
    int week = m_comboBoxWeek->currentData().toInt();
    QPair<QDate, QDate> weekRange = getWeekRange(year, week);
    QDate date = weekRange.first.addDays(day);
    QString time = m_times.at(timeSlot);

    QSqlQuery query;
    if (courseName.isEmpty()) {
        //删除课程
        query.prepare("DELETE FROM schedule WHERE date = ? AND time = ?");
        query.addBindValue(date.toString("yyyy-MM-dd"));
        query.addBindValue(time);
    }else{
        //使用REPLACE语句更新课程信息
        query.prepare("INSERT OR REPLACE INTO schedule (date, time, course_name) VALUES (?, ?, ?)");
        query.addBindValue(date.toString("yyyy-MM-dd"));
        query.addBindValue(time);
        query.addBindValue(courseName);
    }
    if (!query.exec()) {
        QMessageBox::warning(this, tr("Error"), QString(tr("Failed to update course! = ") + query.lastError().text()));
        loadSchedule();//重新加载课程表
    }
}

